package hh.util.bean;


import hh.util.StringUtil;
import jdk.nashorn.internal.codegen.types.BooleanType;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;

/**
 * @author huanghuai
 * @date 2020/9/10
 */
public class ClassUtil implements Serializable {

    public static final String IS_PREFIX = "is";
    public static final String GET_PREFIX = "get";
    public static final String SET_PREFIX = "set";
    private static final long serialVersionUID = -967906452442520069L;

    public static boolean isJavaBeanFieldModifier(Field field) {
        int modifiers = field.getModifiers();
        boolean nonJavaBeanField = Modifier.isFinal(modifiers) || Modifier.isStatic(modifiers) || Modifier.isAbstract(modifiers);
        return !nonJavaBeanField;
    }

    /**
     * 公共 非static 非抽象
     */
    public static boolean isJavaBeanMethodModifier(Method method) {
        int modifiers = method.getModifiers();
        boolean nonJavaBean = Modifier.isStatic(modifiers) || Modifier.isAbstract(modifiers) || !Modifier.isPublic(modifiers);
        return !nonJavaBean;
    }

    public static Method findGetMethod(Field field) {
        Method[] methods = field.getDeclaringClass().getMethods();
        for (Method method : methods) {
            // 检查  方法名  方法修饰符  参数个数=0  返回值不为空
            if (getMethodNameMatch(method, field)
                    && isJavaBeanMethodModifier(method)
                    && method.getParameterCount() == 0
                    && method.getReturnType() != Void.class
                    && method.getReturnType() != void.class) {
                return method;
            }
        }
        return null;
    }

    public static boolean getMethodNameMatch(Method method, Field field) {
        if (isBoolType(field) && method.getName().equals(IS_PREFIX + StringUtil.upperFirst(field.getName()))) {
            return true;
        }

        return method.getName().equals(getterMethodName(field));
    }

    public static Method findSetMethod(Field field) {
        Method[] methods = field.getDeclaringClass().getMethods();
        String setName = setterMethodName(field);
        for (Method method : methods) {
            // 检查  方法名  方法修饰符  参数个数=1  参数类型匹配
            if (method.getName() == setName.intern()
                    && isJavaBeanMethodModifier(method)
                    && method.getParameterCount() == 1
                    && method.getParameterTypes()[0] == field.getType()) {
                return method;
            }
        }
        return null;
    }


    public static String getterMethodName(Field field) {
        return GET_PREFIX + StringUtil.upperFirst(field.getName());
    }

    public static String boolGetMethodName(Field field) {
        return IS_PREFIX + StringUtil.upperFirst(field.getName());
    }

    private static boolean isBoolType(Field field) {
        return field.getType() == Boolean.class || field.getType() == boolean.class;
    }

    public static String setterMethodName(Field field) {
        return SET_PREFIX + StringUtil.upperFirst(field.getName());
    }

    @SuppressWarnings("raw")
    public static <T> T newInstance(Class<T> type) {
        try {
            return type.newInstance();
        } catch (Exception e) {
            throw new IllegalArgumentException(e);
        }
    }

    public static Field[] getMyJavaBeanFields(Class<?> type) {
        return Arrays.stream(type.getDeclaredFields())
                .filter(e -> e.getDeclaringClass() == type && ClassUtil.isJavaBeanFieldModifier(e))
                .toArray(Field[]::new);
    }


    public static boolean matchGetter(Field field, Method getter) {
        return findGetMethod(field) == getter;
    }


    public static boolean matchSetter(Field field, Method setter) {
        return findSetMethod(field) == setter;
    }

}
